home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
os2
/
pmnos11s
/
tcpcmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-30
|
10KB
|
445 lines
/* TCP control and status routines
* Copyright 1991 Phil Karn, KA9Q
*
* Mods by G1EMM
*/
#include <stdio.h>
#if !defined(OS2)
#include <dos.h>
#endif
#include "global.h"
#include "timer.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "tcp.h"
#include "cmdparse.h"
#include "commands.h"
static int doirtt __ARGS((int argc,char *argv[],void *p));
static int domss __ARGS((int argc,char *argv[],void *p));
static int dortt __ARGS((int argc,char *argv[],void *p));
static int dotcpkick __ARGS((int argc,char *argv[],void *p));
static int dotcpreset __ARGS((int argc,char *argv[],void *p));
static int dotcpretries __ARGS((int argc,char *argv[],void *p));
static int dotcpstat __ARGS((int argc,char *argv[],void *p));
static int dotcptimer __ARGS((int argc,char *argv[],void *p));
static int dotcptr __ARGS((int argc,char *argv[],void *p));
static int dowindow __ARGS((int argc,char *argv[],void *p));
static int dosyndata __ARGS((int argc,char *argv[],void *p));
static int doview __ARGS((int argc,char *argv[],void *p));
void rxtx_data_compute __ARGS((struct tcb *tcb,int32 *sent,int32 *recvd));
static int tstat __ARGS((void));
/* TCP subcommand table */
static struct cmds Tcpcmds[] = {
"irtt", doirtt, 0, 0, NULLCHAR,
"kick", dotcpkick, 0, 2, "tcp kick <tcb>",
"mss", domss, 0, 0, NULLCHAR,
"reset", dotcpreset, 0, 2, "tcp reset <tcb>",
"retries", dotcpretries,0,0, NULLCHAR,
"rtt", dortt, 0, 3, "tcp rtt <tcb> <val>",
"status", dotcpstat, 0, 0, NULLCHAR,
"syndata", dosyndata, 0, 0, NULLCHAR,
"timertype", dotcptimer, 0, 0, NULLCHAR,
"trace", dotcptr, 0, 0, NULLCHAR,
"view", doview, 0, 0, NULLCHAR,
"window", dowindow, 0, 0, NULLCHAR,
NULLCHAR,
};
int
dotcp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Tcpcmds,argc,argv,p);
}
static int
dotcptr(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Tcp_trace,"TCP state tracing",argc,argv);
}
/* Eliminate a TCP connection */
static int
dotcpreset(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct tcb *tcb;
#if !defined(OS2)
tcb = MK_FP(htoi(argv[1]),8);
#else
tcb = (struct tcb *)htoi(argv[1]);
#endif
if(!tcpval(tcb)){
tprintf(Notval);
return 1;
}
reset_tcp(tcb);
return 0;
}
/* Set initial round trip time for new connections */
static int
doirtt(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct tcp_rtt *tp;
setlong(&Tcp_irtt,"TCP default irtt",argc,argv);
if(argc < 2){
for(tp = &Tcp_rtt[0];tp < &Tcp_rtt[RTTCACHE];tp++){
if(tp->addr != 0){
if(tprintf("%s: srtt %lu mdev %lu\n",
inet_ntoa(tp->addr),
tp->srtt,tp->mdev) == EOF)
break;
}
}
}
return 0;
}
extern int16 Tcp_retries;
/* Set maximum number of backoffs before resetting the connection */
static int
dotcpretries(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setshort(&Tcp_retries,"max. retries",argc,argv);
}
/* Set smoothed round trip time for specified TCB */
static int
dortt(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct tcb *tcb;
tcb = (struct tcb *)ltop(htol(argv[1]));
if(!tcpval(tcb)){
tprintf(Notval);
return 1;
}
tcb->srtt = atol(argv[2]);
return 0;
}
/* Force a retransmission */
static int
dotcpkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct tcb *tcb;
#if !defined(OS2)
tcb = MK_FP(htoi(argv[1]),8);
#else
tcb = (struct tcb *)htoi(argv[1]);
#endif
if(kick_tcp(tcb) == -1){
tprintf(Notval);
return 1;
}
return 0;
}
/* Set default maximum segment size */
static int
domss(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setshort(&Tcp_mss,"TCP MSS",argc,argv);
}
/* Set default window size */
static int
dowindow(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setshort(&Tcp_window,"TCP window",argc,argv);
}
static int
dosyndata(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Tcp_syndata,"TCP syn+data piggybacking",argc,argv);
}
/* Display status of TCBs */
static int
dotcpstat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct tcb *tcb;
if(argc < 2){
tstat();
} else {
#if !defined(OS2)
tcb = MK_FP(htoi(argv[1]),8);
#else
tcb = (struct tcb *)htoi(argv[1]);
#endif
if(!tcpval(tcb))
tprintf(Notval);
else
st_tcp(tcb);
}
return 0;
}
/* Dump TCP stats and summary of all TCBs
/* &TCB Rcv-Q Snd-Q Local socket Remote socket State
* 1234 0 0 xxx.xxx.xxx.xxx:xxxxx xxx.xxx.xxx.xxx:xxxxx Established
*/
static int
tstat()
{
register int i;
register struct tcb *tcb;
int j;
for(j=i=1;i<=NUMTCPMIB;i++){
if(Tcp_mib[i].name == NULLCHAR)
continue;
tprintf("(%2u)%-20s%10lu",i,Tcp_mib[i].name,
Tcp_mib[i].value.integer);
if(j++ % 2)
tprintf(" ");
else
tprintf("\n");
}
if((j % 2) == 0)
tprintf("\n");
#if !defined(OS2)
tprintf("&TCB Rcv-Q Snd-Q Local socket Remote socket State\n");
#else
tprintf("&TCB Rcv-Q Snd-Q Local socket Remote socket State\n");
#endif
for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
#if !defined(OS2)
tprintf("%4.4x%6u%6u ",FP_SEG(tcb),tcb->rcvcnt,tcb->sndcnt);
#else
tprintf("%8x%6u%6u ",ptol(tcb),tcb->rcvcnt,tcb->sndcnt);
#endif
tprintf("%-23s",pinet(&tcb->conn.local));
tprintf("%-23s",pinet(&tcb->conn.remote));
tprintf("%-s",Tcpstates[tcb->state]);
if(tcb->state == TCP_LISTEN && tcb->flags.clone)
tprintf(" (S)");
if(tprintf("\n") == EOF)
return 0;
}
return 0;
}
/* Dump a TCP control block in detail */
void
st_tcp(tcb)
struct tcb *tcb;
{
int32 sent,recvd;
if(tcb == NULLTCB)
return;
rxtx_data_compute(tcb,&sent,&recvd);
tprintf("Local: %s",pinet(&tcb->conn.local));
tprintf(" Remote: %s",pinet(&tcb->conn.remote));
tprintf(" State: %s\n",Tcpstates[tcb->state]);
tprintf(" Init seq Unack Next Resent CWind Thrsh Wind MSS Queue Total\n");
tprintf("Send:");
tprintf("%9lx",tcb->iss);
tprintf("%9lx",tcb->snd.una);
tprintf("%9lx",tcb->snd.nxt);
tprintf("%7lu",tcb->resent);
tprintf("%6u",tcb->cwind);
tprintf("%6u",tcb->ssthresh);
tprintf("%6u",tcb->snd.wnd);
tprintf("%5u",tcb->mss);
tprintf("%6u",tcb->sndcnt);
tprintf("%11lu\n",sent);
tprintf("Recv:");
tprintf("%9lx",tcb->irs);
tprintf(" ");
tprintf("%9lx",tcb->rcv.nxt);
tprintf("%7lu",tcb->rerecv);
tprintf(" ");
tprintf(" ");
tprintf("%6u",tcb->rcv.wnd);
tprintf(" ");
tprintf("%6u",tcb->rcvcnt);
tprintf("%11lu\n",recvd);
if(tcb->reseq != (struct reseq *)NULL){
register struct reseq *rp;
tprintf("Reassembly queue:\n");
for(rp = tcb->reseq;rp != (struct reseq *)NULL; rp = rp->next){
if(tprintf(" seq x%lx %u bytes\n",
rp->seg.seq,rp->length) == EOF)
return;
}
}
if(tcb->backoff > 0)
tprintf("Backoff %u ",tcb->backoff);
if(tcb->flags.retran)
tprintf("Retrying ");
switch(tcb->timer.state){
case TIMER_STOP:
tprintf("Timer stopped ");
break;
case TIMER_RUN:
tprintf("Timer running (%ld/%ld ms) ",
(long)read_timer(&tcb->timer),
(long)dur_timer(&tcb->timer));
break;
case TIMER_EXPIRE:
tprintf("Timer expired ");
}
tprintf("SRTT %ld ms Mean dev %ld ms\n",tcb->srtt,tcb->mdev);
}
void
rxtx_data_compute(tcb,sent,recvd)
struct tcb *tcb;
int32 *sent;
int32 *recvd;
{
/* Compute total data sent and received; take out SYN and FIN */
*sent = tcb->snd.una - tcb->iss; /* Acknowledged data only */
*recvd = tcb->rcv.nxt - tcb->irs;
switch(tcb->state){
case TCP_LISTEN:
case TCP_SYN_SENT: /* Nothing received or acked yet */
*sent = *recvd = 0;
break;
case TCP_SYN_RECEIVED:
(*recvd)--; /* Got SYN, no data acked yet */
*sent = 0;
break;
case TCP_ESTABLISHED: /* Got and sent SYN */
case TCP_FINWAIT1: /* FIN not acked yet */
(*sent)--;
(*recvd)--;
break;
case TCP_FINWAIT2: /* Our SYN and FIN both acked */
*sent -= 2;
(*recvd)--;
break;
case TCP_CLOSE_WAIT: /* Got SYN and FIN, our FIN not yet acked */
case TCP_CLOSING:
case TCP_LAST_ACK:
(*sent)--;
*recvd -= 2;
break;
case TCP_TIME_WAIT: /* Sent and received SYN/FIN, all acked */
*sent -= 2;
*recvd -= 2;
break;
}
}
static int
doview()
{
register struct tcb *tcb;
int32 sent,recvd;
char temp[40];
#if !defined(PM)
tprintf(" Send Send Receive Receive\n");
tprintf("&TCB Remote Socket:Port:Local Port/State Bytes Retries Bytes Retries\n");
#else
tprintf(" Send Send Receive Receive\n");
tprintf("&TCB Remote Socket:Port:Local Port/State Bytes Retries Bytes Retries\n");
for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
#endif
if(tcb->state == TCP_LISTEN)
continue;
sprintf(temp,"%8lx ",ptol(tcb));
#if !defined(PM)
temp[4]=0;
tprintf("%-4s ",temp);
#else
tprintf("%-8s ",temp);
#endif
strcpy(temp,pinet(&tcb->conn.remote));
strcat(temp,strstr(pinet(&tcb->conn.local),":"));
strcat(temp,"/");
strcat(temp,Tcpstates[tcb->state]);
tprintf("%-37s",temp);
rxtx_data_compute(tcb,&sent,&recvd);
tprintf("%10lu ",sent);
tprintf("%7lu ",tcb->resent);
tprintf("%10lu ",recvd);
tprintf("%7lu",tcb->rerecv);
if(tprintf("\n") == EOF)
return 0;
}
return 0;
}
/* tcp timers type - linear v exponential */
static
dotcptimer(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
extern int tcptimertype;
if (argc < 2) {
tprintf("Tcp timer type is %s\n", tcptimertype ? "linear" : "exponential" ) ;
return 0 ;
}
switch (argv[1][0]) {
case 'l':
case 'L':
tcptimertype = 1 ;
break ;
case 'e':
case 'E':
tcptimertype = 0 ;
break ;
default:
tprintf("use: tcp timertype [linear|exponential]\n") ;
return -1 ;
}
return 0 ;
}